﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.Validation;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Domaine.Entity;
using Infrastructure.Data.Context.UnitOfWork.Mapping;

namespace Infrastructure.Data.UnitOfWork
{
    public class MembershipUnitOfWork:DbContext,IMembershipUnitOfWork
    {

        #region IMembershipUnitOfWork Members

        IDbSet<AspApplication> _AspApplications;
        public IDbSet<AspApplication> AspApplications
        {
            get
            {
                if (_AspApplications == null)
                    _AspApplications = base.Set<AspApplication>();

                return _AspApplications;
            }
        }

        IDbSet<User> _Users;
        public IDbSet<User> Users
        {
            get
            {
                if (_Users == null)
                    _Users = base.Set<User>();

                return _Users;
            }
        }

        IDbSet<Role> _Roles;
        public IDbSet<Role> Roles
        {
            get
            {
                if (_Roles == null)
                    _Roles = base.Set<Role>();

                return _Roles;
            }
        }

        IDbSet<Membership> _Memberships;
        public IDbSet<Membership> Memberships
        {
            get
            {
                if (_Memberships == null)
                    _Memberships = base.Set<Membership>();

                return _Memberships;
            }
        }

        

        #endregion

        #region
        public MembershipUnitOfWork()
            : base("SCORMLMSConnectionStrings")
        {

        }
        #endregion



        #region IQueryableUnitOfWork Members

        public IDbSet<TEntity> CreateSet<TEntity>()
            where TEntity : class
        {
            return base.Set<TEntity>();
        }

        public void Attach<TEntity>(TEntity item)
            where TEntity : class
        {
            //attach and set as unchanged
            base.Entry<TEntity>(item).State = EntityState.Unchanged;
        }

        public void SetModified<TEntity>(TEntity item)
            where TEntity : class
        {
            //this operation also attach item in object state manager
            base.Entry<TEntity>(item).State =  EntityState.Modified;
        }
        public void ApplyCurrentValues<TEntity>(TEntity original, TEntity current)
            where TEntity : class
        {
            //if not is attached, attach original and set current values
            base.Entry<TEntity>(original).CurrentValues.SetValues(current);
        }

        public void Commit()
        {
            try
            {
                base.SaveChanges();
            }
            catch (DbEntityValidationException ex)
            {
                string errors = "";
                foreach (DbEntityValidationResult result in ex.EntityValidationErrors){
                    foreach (DbValidationError err in result.ValidationErrors)
                    {
                        errors+= err.ErrorMessage;
                    }
                }
                throw new Infrastructure.CrossCutting.LMSException(errors);
            }
           
        }

        public void CommitAndRefreshChanges()
        {
            bool saveFailed = false;

            do
            {
                try
                {
                    base.SaveChanges();

                }
                catch (DbUpdateConcurrencyException ex)
                {
                    saveFailed = true;

                    ex.Entries.ToList()
                              .ForEach(entry =>
                              {
                                  entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                              });

                }
            } while (saveFailed);

        }

        public void RollbackChanges()
        {
            // set all entities in change tracker 
            // as 'unchanged state'
            base.ChangeTracker.Entries()
                              .ToList()
                              .ForEach(entry => entry.State = System.Data.EntityState.Unchanged);
        }

        public IEnumerable<TEntity> ExecuteQuery<TEntity>(string sqlQuery, params object[] parameters)
        {
            return base.Database.SqlQuery<TEntity>(sqlQuery, parameters);
        }

        public int ExecuteCommand(string sqlCommand, params object[] parameters)
        {
            return base.Database.ExecuteSqlCommand(sqlCommand, parameters);
        }

        #endregion

        #region DbContext Overrides

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //Remove unused conventions
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
            modelBuilder.Configurations.Add(new AspApplicationMapper());
            modelBuilder.Configurations.Add(new MembershipMapping());
            modelBuilder.Configurations.Add(new RoleMapper());
            modelBuilder.Configurations.Add(new UserMapper());
        }
        #endregion
    }
}
